// src/timer/SafeTimer.impl.ts

import dayjs from 'dayjs';
import type { Timer, TimerState, TimeUnit } from './types.mts';

type Callback = () => void;

/**
 * 毫秒数归一化工具
 * @param value 数值
 * @param unit 单位
 */
const toMs = (value: number, unit: TimeUnit): number => {
  if (unit === 'second') return value * 1000;
  if (unit === 'minute') return value * 60 * 1000;
  return value; // 已经是毫秒
};

/**
 * 防止内存泄漏的核心实现
 * 通过闭包持有可被外部清除的 timeoutId，并确保 callback 不会持有外部引用
 */
class SafeTimer implements Timer {
  private _state: TimerState = 'idle';
  private timerId: NodeJS.Timeout | number | null = null;
  private startAt = 0; // 开始/恢复时刻的 timestamp
  private remaining = 0; // 暂停时剩余的毫秒数
  private readonly delayMs: number;
  private readonly callback: Callback;
  private readonly immediate: boolean;

  constructor(
    delay: number,
    unit: TimeUnit,
    callback: Callback,
    immediate = false,
  ) {
    this.delayMs = toMs(delay, unit);
    this.callback = callback;
    this.immediate = immediate;
    this.remaining = this.delayMs;

    // 立即执行一次（如果需要）
    if (immediate) {
      this.callback();
    }

    this._state = 'running';
    this.startAt = dayjs().valueOf();
    this.schedule();
  }

  get state(): TimerState {
    return this._state;
  }

  private schedule() {
    // 关键：使用箭头函数避免 this 绑定问题，同时不持有外部强引用
    this.timerId = setTimeout(() => {
      this.callback();
      // 继续下一次循环
      if (this._state === 'running') {
        this.startAt = dayjs().valueOf();
        this.remaining = this.delayMs;
        this.schedule();
      }
    }, this.remaining);
  }

  /** 暂停：计算剩余时间，清除 timeout */
  pause() {
    if (this._state !== 'running') return;

    this.remaining -= dayjs().valueOf() - this.startAt;
    if (this.timerId !== null) {
      clearTimeout(this.timerId as number);
      this.timerId = null;
    }
    this._state = 'paused';
  }

  /** 恢复：从剩余时间继续 */
  resume() {
    if (this._state !== 'paused') return;

    this._state = 'running';
    this.startAt = dayjs().valueOf();
    this.schedule();
  }

  /** 彻底销毁，防止任何内存泄漏 */
  destroy() {
    if (this.timerId !== null) {
      clearTimeout(this.timerId as number);
      this.timerId = null;
    }
    this._state = 'idle';
  }

  /** 重启：可选择立即执行一次 */
  restart(immediate?: boolean) {
    // Don't destroy completely, just stop the current timer
    if (this.timerId !== null) {
      clearTimeout(this.timerId as number);
      this.timerId = null;
    }

    this.remaining = this.delayMs;
    this._state = 'running';
    this.startAt = dayjs().valueOf();

    if (immediate ?? this.immediate) {
      this.callback();
    }

    this.schedule();
  }
}

/**
 * 函数式 API：推荐的简洁用法
 * 返回的 Timer 实例可链式调用 pause/resume/destroy
 *
 * @param delay   间隔数值
 * @param unit    时间单位，支持 second/minute/毫秒数
 * @param callback 每次触发的回调
 * @param immediate 是否立即执行一次（类似 setInterval 行为）
 */
export const setTimer = (
  delay: number,
  unit: TimeUnit,
  callback: () => void,
  immediate = false,
): Timer => {
  return new SafeTimer(delay, unit, callback, immediate);
};
